#pragma once

#include <mutex>

namespace xrtc {

template <typename T>
class ThreadSafeQueue {
private:
    struct Node {
        T value;
        Node* next;

        Node(const T& value) : value(value), next(nullptr) {} 
    };

    Node* first;
    Node* divider;
    Node* last;
    int m_size;
    mutable std::mutex m_mutex;

public:
    ThreadSafeQueue() {
        first = divider = last = new Node(T());
        m_size = 0;
    }

    ~ThreadSafeQueue() {
        std::lock_guard<std::mutex> lock(m_mutex);
        while (first != nullptr) {
            Node* temp = first;
            first = first->next;
            delete temp;
        }
        m_size = 0;
    }

    void produce(const T& t) {
        std::lock_guard<std::mutex> lock(m_mutex);
        last->next = new Node(t);
        last = last->next;
        ++m_size;

        while (divider != first) {
            Node* temp = first;
            first = first->next;
            delete temp;
        }
    }

    bool consume(T* result) {
        std::lock_guard<std::mutex> lock(m_mutex);
        if (divider != last) {
            *result = divider->next->value;
            divider = divider->next;
            --m_size;
            return true;
        }
        return false;
    }

    bool empty() const {
        std::lock_guard<std::mutex> lock(m_mutex);
        return m_size == 0;
    }

    int size() const {
        std::lock_guard<std::mutex> lock(m_mutex);
        return m_size;
    }
};

} // namespace xrtc